/**
  ******************************************************************************
  * @file           : flash.c
  * @brief          : Internel flash program function
  * @author         : Qilong Huang <jcdiyhelp@qq.com>
  * @date           : 2021-06-08 
  * 
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2021 Joy create tech(Suzhou, China) Co., Ltd.
  * All rights reserved.
  *
  *
  ******************************************************************************
  */
/* Global include ---------------------------------------------------------*/
#include "flash.h"
#include "stm32l1xx_hal_flash_ex.h"
/* Global define ------------------------------------------------------------*/
TYP_FlashHalfPage_t FlashHalfBuffer;
/* Private declaration -----------------------------------------------------*/
extern void FLASH_PageErase(UINT32_t PageAddress);
UINT32_t x_p[32] = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
                    0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
                    0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
                    0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
                    0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
                    0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
                    0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
                    0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF};
/**
 * @brief   Read bytes from Flash
 * @param   Addr   Start address you wanna to read, from 0~0xFFF(4096)
 * @return  Data read out
 */
UINT8_t FLASH_ReadByte(UINT32_t Addr)
{
    TYP_MEMORY UINT32_t *wAddr;
    UINT8_t RetVal;
    if ((Addr >= AppSWAddress) && (Addr < AppSWAddress + FlashVaildLen))
    {
        wAddr = (UINT32_t *)(Addr);
        RetVal = (UINT8_t)*wAddr;
    }
    return RetVal;
}

/**
 * @brief   Read one word from Flash
 * @param   Addr   Start address you wanna to read, from 0~0xFFF(4096)
 * @return  Data read out
 */
volatile UINT32_t FLASH_ReadWord(UINT32_t Addr)
{
    TYP_MEMORY UINT32_t *wAddr;
    UINT32_t RetVal;
    if ((Addr >= AppSWAddress) && (Addr < AppSWAddress + FlashVaildLen))
    {
        wAddr = (UINT32_t *)(Addr);
        RetVal = (UINT32_t)*wAddr;
    }
    return RetVal;
}

/**
 * @brief   Write one byte to EEPROM
 * @param   Addr   Start address you wanna to write(from AppSWAddress to AppSWAddress + FlashVaildLen)
 * @param   Data   Byte to write
 * @return  Function states
 */
TYP_funcRetrun_t FLASH_WriteAWord(UINT32_t Addr, UINT32_t Data)
{
    TYP_MEMORY UINT8_t *wAddr;
    TYP_funcRetrun_t RetVal = TYP_FAIL;
    if ((Addr >= AppSWAddress) && (Addr < AppSWAddress + FlashVaildLen))
    {
        if(Addr % 4 == 0)
        {
            HAL_FLASH_Unlock();
            while(HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, (UINT32_t) Addr, (UINT32_t)Data) != HAL_OK);                       
            HAL_FLASH_Lock();
            RetVal = TYP_SUCCESS;
        }
        else
        {
            RetVal = TYP_ADDRESS_NOT_ALLIGN;
        }
    }
    else
    {
        RetVal = TYP_ADDRESS_OVERFLAOW;
    }
    return RetVal;
}

/**
 * @brief   Write half page(32 words -- 128 bytes) to flash
 * @param   Addr   Start address you wanna to write(from AppSWAddress to AppSWAddress + FlashVaildLen)
 * @param   Data   Word data buffer pointer
 * @return  Function states
 */
TYP_funcRetrun_t FLASH_WriteHalfPage(UINT32_t Addr, UINT32_t * Data)
{
    TYP_MEMORY UINT8_t *wAddr;
    TYP_funcRetrun_t RetVal = TYP_FAIL;
    if ((Addr >= AppSWAddress) && (Addr < AppSWAddress + FlashVaildLen))
    {
        HAL_FLASH_Unlock();
        while(HAL_FLASHEx_HalfPageProgram((UINT32_t)Addr, (uint32_t *)Data) != HAL_OK);                       
        HAL_FLASH_Lock();
        RetVal = TYP_SUCCESS;
    }
    else
    {
        RetVal = TYP_ADDRESS_OVERFLAOW;
    }
    return RetVal;
}

/**
 * @brief   Erase the application area
 * @param   StartAddress   APP SW start address
 * @param   EndAddress     APP SW end address
 * @return  Function states
 */
void FLASH_EraseAppArea(UINT32_t StartAddress, UINT32_t EndAddress)
{
    UINT32_t TempAddr;
    HAL_FLASH_Unlock();
    for (TempAddr = StartAddress; TempAddr < EndAddress; TempAddr += FLASH_PAGE_SIZE)
    {
        FLASH_PageErase(TempAddr);
    }
    HAL_FLASH_Lock();
}

/**
 * @brief   Read half page(32 words -- 128 bytes) to buffer
 * @param   Addr   Start address you wanna to write(from AppSWAddress to AppSWAddress + FlashVaildLen)
 * @param   Data   Word data buffer pointer
 * @return  Function states
 */
TYP_funcRetrun_t FLASH_ReadHalfPage(UINT32_t Addr, UINT32_t * Data)
{
    TYP_MEMORY UINT32_t *wAddr;
    TYP_funcRetrun_t RetVal = TYP_SUCCESS;
    int i;
    if(Addr % 128 != 0)
    {
        RetVal = TYP_ADDRESS_NOT_ALLIGN;
    }
    else
    {
        if ((Addr >= AppSWAddress) && (Addr < AppSWAddress + FlashVaildLen))
        {
					  for(i = 0; i < 32; i ++)
            {
                (*(Data ++)) = FLASH_ReadWord(Addr + 4 * i);
            }
            
            RetVal = TYP_SUCCESS;
        }
        else
        {
            RetVal = TYP_ADDRESS_OVERFLAOW;
        }
    }
    return RetVal;
}
